package com.neoCalf.neoGateway.filter;

import com.alibaba.fastjson.JSONObject;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.neoCalf.neoCommon.enums.ResultCode;
import com.neoCalf.neoCommon.enums.RoleEnum;
import com.neoCalf.neoCommon.model.R;
import com.neoCalf.neoGateway.properties.AppContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;

import javax.annotation.Resource;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 小牛
 * @version 1.0
 * &#064;description  认证过滤器
 * 用于验证用户身份和权限的过滤器，在请求到达微服务之前进行拦截。
 * &#064;date  2025/4/7 23:09
 */
@Component
@Slf4j
public class AuthenticationFilter implements GatewayFilter {
    @Resource
    private AppContext appContext;
    // 在网关初始化时创建专用线程池
    private static final ExecutorService URL_ENCODING_EXECUTOR =
            Executors.newFixedThreadPool(
                    Runtime.getRuntime().availableProcessors() * 2,  // 通常CPU核数×2
                    new ThreadFactoryBuilder()
                            .setNameFormat("url-encoder-pool-%d")
                            .setDaemon(true)
                            .build()
            );

    private final WebClient.Builder webClientBuilder;

    public AuthenticationFilter(WebClient.Builder webClientBuilder) {
        this.webClientBuilder = webClientBuilder;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取请求头中的Authorization（JWT Token）
        List<String> token = exchange.getRequest().getHeaders().get("token");
        if (token == null || token.isEmpty() || token.get(0).isEmpty()) {
            return unauthorizedResponse(exchange, R.fail(ResultCode.CODE_10015));
        }
        String uri = appContext.getAuthIp() + appContext.getAuthPath() + "?" + "token" + "=" + token.get(0) + "&" + "role" + "=" + buildRoleEnum(exchange.getRequest().getPath().toString()).getRole();
        // 调用认证微服务验证Token的有效性
        return webClientBuilder.build()
                .get()
                .uri(uri)  // 调用认证微服务的验证接口
                .retrieve()
                .bodyToMono(R.class)
                .flatMap(R -> {
                    if (Objects.equals(R.getCode(), ResultCode.Success.getCode())) {
                        // Token有效，继续处理请求
                        Map<String, Object> data = (Map<String, Object>) R.getResult();
                        if (data != null) {
                            try {
                                exchange.getRequest().mutate()
                                        .header("userId", String.valueOf(data.get("userId")))
                                        .header("role", String.valueOf(data.get("role")))
                                        .header("nickName", asyncUrlEncode(String.valueOf(data.get("nickName"))).get()).build();
                            } catch (ExecutionException | InterruptedException e) {
                                log.error("URL编码失败", e);
                                return Mono.error(new RuntimeException(e));
                            }
                        }
                        return chain.filter(exchange);
                    } else {
                        return unauthorizedResponse(exchange, R);
                    }
                });
    }

    private Mono<Void> unauthorizedResponse(ServerWebExchange exchange, R R) {
// 创建响应的 JSON 内容
        String jsonResponse = JSONObject.toJSONString(R);
        // 将 JSON 转化为 ByteBuffer
        DataBufferFactory bufferFactory = exchange.getResponse().bufferFactory();
        DataBuffer dataBuffer = bufferFactory.wrap(jsonResponse.getBytes(StandardCharsets.UTF_8));
        // 设置响应头 Content-Type 为 application/json
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
        // 将 JSON 写入响应体
        return exchange.getResponse().writeWith(Mono.just(dataBuffer));
    }

    private RoleEnum buildRoleEnum(String path) {
        for (String adminPath : appContext.getAdminPaths()) {
            if (path.startsWith(adminPath)) {
                return RoleEnum.ADMIN;
            }
        }
        return RoleEnum.USER;
    }

    // 使用CompletableFuture进行异步URL编码
    public CompletableFuture<String> asyncUrlEncode(String value) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
            } catch (UnsupportedEncodingException e) {
                log.error("URL编码失败", e);
                throw new RuntimeException(e);
            }
        }, URL_ENCODING_EXECUTOR); // 使用专用线程池
    }
}
